Micron Document
πŸŽ–οΈGitΠ―Ρ€Π°πŸŽ–οΈ

Commit 2e6730d1e3262022818edfbc23330fbc2d607adf


Parents : dea9d86
Author : James Rich <2199651+jamesarich@users.noreply.github.com>
Signature : Signature validation error
Date : 2026-04-23T16:33:16-05:00
Committer : GitHub <noreply@github.com>
Date : 2026-04-23T21:33:16Z

fix(desktop): unbreak release crash via correct ProGuard rules (#5236)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Changes
Diff

diff --git a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt
index d3cfceb2a3..4169f88413 100644
--- a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt
+++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt
@@ -44,17 +44,16 @@ internal fun Project.configureAndroidCompose(commonExtension: CommonExtension) {
"androidx.compose.runtime",
"androidx.compose.ui",
)
-
- // The BOM exclusion above strips versions from transitive material deps
- // (e.g. maps-compose-widgets, datadog). Pin the material group to the
- // AndroidX version that matches this CMP release.
+ // The BOM exclusion above strips the version from `androidx.compose.material:material`
+ // requested by maps-compose-widgets (google flavor). Pin only that artifact β€” the
+ // group also contains `material-ripple`, which CMP publishes at the bom-aligned
+ // version and must not be force-downgraded.
val materialVersion = libs.version("androidx-compose-material")
-
configurations.configureEach {
resolutionStrategy.eachDependency {
if (requested.group in cmpAlignedGroups) {
useVersion(androidxComposeVersion)
- } else if (requested.group == "androidx.compose.material") {
+ } else if (requested.group == "androidx.compose.material" && requested.name == "material") {
useVersion(materialVersion)
}
}

diff --git a/config/proguard/shared-rules.pro b/config/proguard/shared-rules.pro
index 8d0d8efde0..eb4ebd7fd3 100644
--- a/config/proguard/shared-rules.pro
+++ b/config/proguard/shared-rules.pro
@@ -1,166 +1,135 @@
# ============================================================================
# Meshtastic β€” Shared ProGuard / R8 rules
# ============================================================================
-# Cross-platform keep and dontwarn rules applied to BOTH the Android app
-# release build (R8) and the Desktop distribution (ProGuard). Host-specific
-# rules live in the per-module proguard-rules.pro file.
+# Cross-platform keep rules applied to BOTH the Android app release (R8) and
+# the Desktop distribution (ProGuard 7.7 invoked by compose-jb).
#
-# Rule of thumb: anything describing a library shared between Android and
-# Desktop (Koin, kotlinx-serialization, Wire, Room KMP, Ktor, Coil 3, Kable,
-# Kermit, Okio, DataStore, Paging, Lifecycle / Navigation 3, AboutLibraries,
-# Markdown renderer, QRCode, Compose Multiplatform resources, core modules)
-# belongs here. Anything platform-specific (AWT/Skiko/JNA, AIDL, Android
-# framework, JDK-version quirks, flavor specifics) stays in the host file.
+# IMPORTANT: compose-jb's standalone ProGuard task does NOT auto-include
+# `META-INF/proguard/*.pro` consumer rules from dependency jars (only R8 on
+# Android does β€” https://github.com/Guardsquare/proguard/issues/423).
+# So this file inlines all the consumer rules we depend on for desktop. On
+# Android these are duplicates of what R8 already auto-discovers, which is
+# harmless. Per JetBrains compose-multiplatform docs: keep it as a single
+# static .pro file and add rules as shrinking surfaces problems.
# ============================================================================
# ---- Attributes -------------------------------------------------------------
+-keepattributes SourceFile,LineNumberTable,*Annotation*,Signature,InnerClasses,EnclosingMethod,Exceptions,RuntimeVisibleAnnotations,AnnotationDefault
+
+# ---- Compose Multiplatform 1.11 optimizer defense (#5146) -------------------
+# CMP 1.11 ships consumer rules with `-assumenosideeffects` on
+# Composer.<clinit>() / ComposerImpl.<clinit>() and `-assumevalues` on
+# ComposeRuntimeFlags / ComposeStackTraceMode. The primary defence is
+# `-dontoptimize` (set per-host in app/desktop proguard-rules.pro), which
+# disables rewriting of these directives. Broad package-wide keeps below have
+# been removed per R8_Configuration_Analysis.md as they are redundant β€” rely
+# instead on CMP's own consumer rules + @DoNotInline annotations. If animations
+# freeze in a future CMP/KGP release, replace with class-level keeps on the
+# specific failure points (Composer, ComposerImpl, ComposeRuntimeFlags,
+# ComposeStackTraceMode) rather than package-wide wildcards.
-# Preserve line numbers for meaningful stack traces, plus metadata needed for
-# reflective serializer/DI/Room lookups.
--keepattributes SourceFile,LineNumberTable,*Annotation*,Signature,InnerClasses,EnclosingMethod,Exceptions,RuntimeVisibleAnnotations
-
-# ---- Kotlin / Coroutines ----------------------------------------------------
-# Kotlin stdlib and kotlinx-coroutines ship their own consumer ProGuard rules
-# (kotlin-stdlib and kotlinx-coroutines-core consumer-rules.pro) which keep
-# Metadata, Continuation, kotlin.reflect internals, and debug metadata. No
-# explicit wildcards needed here.
-
-# ---- Koin DI (reflection-based injection) -----------------------------------
-
-# Prevent R8 from merging exception classes (observed as io.ktor.http.URLDecodeException
-# replacing Koin's InstanceCreationException in stack traces, making crashes
-# undiagnosable). Broadened to all of koin core to cover the KSP-generated graph.
--keep class org.koin.** { *; }
--dontwarn org.koin.**
+# ---- Compose Multiplatform resources ----------------------------------------
+-keep class org.meshtastic.core.resources.Res { *; }
+-keepclassmembers class org.meshtastic.core.resources.Res$* { *; }
-# Keep Koin-annotated modules/components so Koin Annotations (KSP) output
-# survives tree-shaking.
+# ---- Koin Annotations (KSP-generated DI graph) ------------------------------
-keep @org.koin.core.annotation.Module class * { *; }
-keep @org.koin.core.annotation.ComponentScan class * { *; }
-keep @org.koin.core.annotation.Single class * { *; }
-keep @org.koin.core.annotation.Factory class * { *; }
-keep @org.koin.core.annotation.KoinViewModel class * { *; }
-# ---- kotlinx-serialization --------------------------------------------------
-
--keep class kotlinx.serialization.** { *; }
--dontwarn kotlinx.serialization.**
-
-# Keep @Serializable classes and their generated $serializer companions
+# ---- kotlinx.coroutines (inlined from coroutines.pro consumer rules) --------
+-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
+-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
+-keepclassmembers class kotlinx.coroutines.** {
+ volatile <fields>;
+}
+-keepclassmembers class kotlin.coroutines.SafeContinuation {
+ volatile <fields>;
+}
+-dontwarn java.lang.instrument.ClassFileTransformer
+-dontwarn sun.misc.SignalHandler
+-dontwarn java.lang.instrument.Instrumentation
+-dontwarn sun.misc.Signal
+-dontwarn java.lang.ClassValue
+-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
+
+# ---- kotlinx.serialization (inlined from kotlinx-serialization-common.pro) --
-keepclassmembers @kotlinx.serialization.Serializable class ** {
static ** Companion;
+}
+-if @kotlinx.serialization.internal.NamedCompanion class *
+-keepclassmembers class * {
+ static <1> *;
+}
+-if @kotlinx.serialization.Serializable class ** {
+ static **$* *;
+}
+-keepclassmembers class <2>$<3> {
kotlinx.serialization.KSerializer serializer(...);
}
--keep class **.$serializer { *; }
--keepclassmembers class **.$serializer { *; }
--keepclasseswithmembers class ** {
+-if @kotlinx.serialization.Serializable class ** {
+ public static ** INSTANCE;
+}
+-keepclassmembers class <1> {
+ public static <1> INSTANCE;
kotlinx.serialization.KSerializer serializer(...);
}
+-dontnote kotlinx.serialization.**
+-dontwarn kotlinx.serialization.internal.ClassValueReferences
+-keepclassmembers public class **$$serializer {
+ private ** descriptor;
+}
+
+# ---- kotlinx.datetime (inlined from datetime.pro consumer rules) ------------
+-dontwarn kotlinx.serialization.KSerializer
+-dontwarn kotlinx.serialization.Serializable
+
+# ---- Ktor (inlined from ktor.pro + ServiceLoader gap) -----------------------
+-keepclassmembers class io.ktor.** {
+ volatile <fields>;
+}
+-keepclassmembernames class io.ktor.** {
+ volatile <fields>;
+}
+-keep class io.ktor.client.engine.** implements io.ktor.client.HttpClientEngineContainer
+# ktor consumer rules preserve the ServiceLoader META-INF/services file but not
+# the impl classes; ContentNegotiation discovers KotlinxSerializationJsonExtensionProvider
+# reflectively and crashes with ServiceConfigurationError without these.
+-keep class * implements io.ktor.serialization.kotlinx.KotlinxSerializationExtensionProvider { *; }
+-keep class io.ktor.serialization.kotlinx.json.** { *; }
+
+# ---- androidx.annotation.Keep (inlined from androidx-annotations.pro) -------
+-keep,allowobfuscation @interface androidx.annotation.Keep
+-keep @androidx.annotation.Keep class * {*;}
+-keepclasseswithmembers class * { @androidx.annotation.Keep <methods>; }
+-keepclasseswithmembers class * { @androidx.annotation.Keep <fields>; }
+-keepclasseswithmembers class * { @androidx.annotation.Keep <init>(...); }
+-keepclassmembers,allowobfuscation class * {
+ @androidx.annotation.DoNotInline <methods>;
+}
-# ---- Wire Protobuf ----------------------------------------------------------
+# ---- androidx.datastore (inlined from datastore-preferences-core.pro) -------
+-keepclassmembers class * extends androidx.datastore.preferences.protobuf.GeneratedMessageLite {
+ <fields>;
+}
-# Wire generates an ADAPTER static field on every Message subclass accessed
-# reflectively during encoding/decoding. Keep those fields and the
-# ProtoAdapter subclasses themselves; Wire's bundled consumer rules preserve
-# the runtime itself.
+# ---- Wire Protobuf (no consumer rules shipped) ------------------------------
-keepclassmembers class * extends com.squareup.wire.Message {
public static *** ADAPTER;
}
-keepclassmembers class * extends com.squareup.wire.ProtoAdapter { *; }
-# Suppress warnings about missing Android Parcelable (Wire cross-platform stubs
-# when compiling for non-Android JVM targets; harmless on Android).
--dontwarn android.os.Parcel**
--dontwarn android.os.Parcelable**
+# ---- androidx.sqlite bundled driver (JNI native bridge) ---------------------
+# androidx.sqlite-bundled's consumer rule keeps native methods only β€” but the
+# bundled JNI library calls back into JVM methods on the driver class
+# (e.g. `nativeThreadSafeMode`). Keep the whole driver package.
+-keep class androidx.sqlite.driver.bundled.** { *; }
+-keepclassmembers class androidx.sqlite.driver.bundled.** { native <methods>; *; }
# ---- Room KMP (room3) -------------------------------------------------------
-
-# Preserve generated database constructors (Room uses reflection to instantiate)
-keep class * extends androidx.room3.RoomDatabase { <init>(); }
-keep class * implements androidx.room3.RoomDatabaseConstructor { *; }
-
-# Keep the expect/actual MeshtasticDatabaseConstructor + database surface
-keep class org.meshtastic.core.database.MeshtasticDatabaseConstructor { *; }
-keep class org.meshtastic.core.database.MeshtasticDatabase { *; }
-
-# Room's own consumer rules (from androidx.room3) keep DAOs, entities,
-# generated _Impl classes, and TypeConverters referenced from the database.
-
-# ---- SQLite bundled --------------------------------------------------------
-# androidx.sqlite ships consumer rules.
-
-# ---- Ktor (ServiceLoader + plugin discovery) --------------------------------
-
-# Keep ServiceLoader metadata files (ktor discovers HttpClientEngineFactory
-# implementations reflectively via ServiceLoader).
--keepclassmembers class * implements io.ktor.client.HttpClientEngineFactory { *; }
-
-# ---- Coil 3 (image loading) -------------------------------------------------
-# coil3 ships consumer rules.
-
-# ---- Kable BLE --------------------------------------------------------------
-# com.juul.kable ships consumer rules; if release builds fail with missing
-# Kable classes, restore a narrow keep for the specific reflection-loaded type.
-
-# ---- Compose Multiplatform resources ----------------------------------------
-
-# Generated resource accessor classes (Res.string.*, Res.drawable.*, etc.).
-# Without these the fdroid flavor has crashed at startup with a misleading
-# URLDecodeException due to R8 exception-class merging.
--keep class org.jetbrains.compose.resources.** { *; }
--keep class org.meshtastic.core.resources.Res { *; }
--keepclassmembers class org.meshtastic.core.resources.Res$* { *; }
-
-# ---- AboutLibraries ---------------------------------------------------------
-# com.mikepenz.aboutlibraries ships consumer rules.
-
-# ---- Multiplatform Markdown Renderer ----------------------------------------
-# com.mikepenz.markdown ships consumer rules.
-
-# ---- QR Code Kotlin ---------------------------------------------------------
-
--keep class io.github.g0dkar.qrcode.** { *; }
--dontwarn io.github.g0dkar.qrcode.**
--keep class qrcode.** { *; }
--dontwarn qrcode.**
-
-# ---- Kermit logging ---------------------------------------------------------
-# co.touchlab.kermit ships consumer rules.
-
-# ---- Okio -------------------------------------------------------------------
-# okio ships consumer rules.
-
-# ---- DataStore --------------------------------------------------------------
-# androidx.datastore ships consumer rules.
-
-# ---- Paging -----------------------------------------------------------------
-# androidx.paging ships consumer rules.
-
-# ---- Lifecycle / Navigation 3 / ViewModel (JetBrains forks) -----------------
-# androidx.lifecycle and androidx.navigation3 ship consumer rules.
-
-# ---- Meshtastic shared model ------------------------------------------------
-# core.model types are reached via static references from Koin-wired graphs,
-# Room entities, and kotlinx-serialization @Serializable companions β€” all of
-# which have their own keep rules above.
-
-# ---- Compose Runtime & Animation --------------------------------------------
-
-# Defence-in-depth: prevent tree-shaking of Compose infrastructure classes that
-# are referenced indirectly through compiler-generated state machines. Applies
-# to BOTH R8 (Android app) and ProGuard (desktop distribution).
-#
-# Why shared: CMP 1.11 ships consumer rules with -assumenosideeffects on
-# Composer.<clinit>() / ComposerImpl.<clinit>() and -assumevalues on
-# ComposeRuntimeFlags / ComposeStackTraceMode. If the optimizer runs (R8 full
-# mode on Android, ProGuard with optimize.set(true) on desktop) these call
-# sites can be rewritten even when the target classes are kept, causing the
-# recomposer / frame-clock / animation state machines to silently freeze on
-# the first frame. -dontoptimize (set per-host) is the primary defence; these
-# keep rules are a safety net against future toolchain changes. See #5146.
--keep class androidx.compose.runtime.** { *; }
--keep class androidx.compose.ui.** { *; }
--keep class androidx.compose.animation.core.** { *; }
--keep class androidx.compose.animation.** { *; }
--keep class androidx.compose.foundation.** { *; }
--keep class androidx.compose.material3.** { *; }

diff --git a/desktop/build.gradle.kts b/desktop/build.gradle.kts
index 58caf800b5..2e66d60122 100644
--- a/desktop/build.gradle.kts
+++ b/desktop/build.gradle.kts
@@ -99,6 +99,12 @@ val generateBuildConfig =
sourceSets.main { kotlin.srcDir(generateBuildConfig.map { buildConfigOutputDir }) }
+// ── ProGuard configuration ───────────────────────────────────────────────────
+// compose-jb's standalone ProGuard 7.7 task does NOT auto-include
+// `META-INF/proguard/*.pro` consumer rules from dependency jars (only R8 on
+// Android does). We therefore inline every keep rule we need into the two
+// static .pro files referenced below.
+
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(21))

diff --git a/desktop/proguard-rules.pro b/desktop/proguard-rules.pro
index 9a9653e87e..f02c2c6cd1 100644
--- a/desktop/proguard-rules.pro
+++ b/desktop/proguard-rules.pro
@@ -1,113 +1,64 @@
# ============================================================================
# Meshtastic Desktop β€” ProGuard rules for release minification
# ============================================================================
-# Open-source project: we rely on tree-shaking (unused code removal) for size
-# reduction. Obfuscation is disabled in build.gradle.kts (obfuscate.set(false)).
+# Open-source: obfuscation is OFF (build.gradle.kts: obfuscate.set(false)).
+# Tree-shaking still runs.
#
-# Cross-platform library rules (Koin, kotlinx-serialization, Wire, Room,
-# Ktor, Coil, Kable, Kermit, Okio, DataStore, Paging, Lifecycle, Navigation 3,
-# AboutLibraries, Markdown, QRCode, CMP resources, core model) live in
-# config/proguard/shared-rules.pro and are wired in by this module's
-# build.gradle.kts. This file holds only desktop/JVM-specific rules.
+# Two rule sources are merged into the ProGuard run:
+# 1. JetBrains' bundled `default-compose-desktop-rules.pro` (auto-injected
+# by the compose.desktop Gradle plugin).
+# 2. Cross-platform project keeps in config/proguard/shared-rules.pro,
+# which inlines every dependency consumer rule we need on desktop β€”
+# compose-jb's standalone ProGuard task does NOT auto-discover
+# `META-INF/proguard/*.pro` consumer rules from dependency jars (only
+# R8 on Android does β€” https://github.com/Guardsquare/proguard/issues/423).
+#
+# This file only holds desktop/JVM-specific rules that aren't covered above.
# ============================================================================
-# ---- General ----------------------------------------------------------------
-
-# Suppress notes about duplicate resource files (common in fat JARs)
--dontnote **
+# ---- ProGuard 7.7 + Kotlin 2.3 metadata workaround --------------------------
+# ProGuard 7.7's KotlinShrinker NPEs on metadata produced by CMP 1.11 +
+# Kotlin 2.3.x. Because we don't obfuscate, class names stay stable and
+# metadata references remain valid without rewriting. Annotations themselves
+# are preserved by `-keepattributes *Annotation*` in shared-rules.pro.
+# (R8-only directive equivalent does not exist; this is ProGuard-only.)
+-dontprocesskotlinmetadata
-# Disable ProGuard optimization passes. Tree-shaking (unused code removal) still
-# runs β€” only method-body rewrites and call-site transformations are suppressed.
-#
-# Why: CMP 1.11 ships consumer rules with -assumenosideeffects on
-# Composer.<clinit>() and ComposerImpl.<clinit>(), plus -assumevalues on
-# ComposeRuntimeFlags and ComposeStackTraceMode. These optimization directives
-# let the optimizer rewrite *call sites* (class-init triggers, flag reads) even
-# when the target classes are preserved by -keep rules. The result is that the
-# Compose recomposer/frame-clock/animation state machines silently freeze on
-# their first frame in release builds. -dontoptimize is the only directive that
-# disables processing of -assumenosideeffects/-assumevalues. The desktop compose
-# build sets optimize.set(true), so this applies here as well as to R8. See #5146.
+# ---- Disable optimizer (CMP 1.11 -assumenosideeffects defense) --------------
+# See shared-rules.pro for full rationale. Even though build.gradle.kts sets
+# `optimize.set(true)` so compose-jb wires the optimization step, this rule
+# turns it into a no-op β€” keeping CMP's `-assumenosideeffects` directives from
+# rewriting Composer call sites and freezing the runtime. See #5146.
-dontoptimize
-# Do not parse/rewrite Kotlin metadata during shrinking/optimization.
-# ProGuard's KotlinShrinker cannot handle the metadata produced by Compose
-# Multiplatform 1.11.x + Kotlin 2.3.x, causing a NullPointerException.
-# Since we disable obfuscation (class names remain stable), metadata references
-# stay valid and do not need rewriting. The annotations themselves are preserved
-# by -keepattributes *Annotation*.
-#
-# NOTE: -dontprocesskotlinmetadata is a ProGuard-only directive; R8 does not
-# recognize it, which is why it lives in the desktop-only file.
--dontprocesskotlinmetadata
-
# ---- Entry point ------------------------------------------------------------
-# (org.meshtastic.desktop.MainKt is covered by the package-wide keep below.)
-
-# ---- Meshtastic desktop host shell ------------------------------------------
-
-# Keep all desktop module classes (thin host shell β€” not worth tree-shaking)
+# Keep the desktop host shell (thin module β€” not worth tree-shaking).
-keep class org.meshtastic.desktop.** { *; }
# ---- JVM runtime suppression ------------------------------------------------
-
-dontwarn java.lang.reflect.**
-dontwarn sun.misc.Unsafe
-dontwarn java.lang.invoke.**
-# ---- jSerialComm (cross-platform serial library with Android stubs) ---------
-
+# ---- jSerialComm Android stubs (cross-platform serial library) --------------
+# jSerialComm bundles Android shims that reference android.* classes; harmless
+# on JVM/desktop but ProGuard fails the build on unresolved program classes
+# unless suppressed.
-dontwarn com.fazecast.jSerialComm.android.**
-# ---- Kotlin stdlib atomics (Kotlin 2.3+ intrinsics, not on JDK 17) ----------
+# Wire ships AndroidMessage in its common runtime; on desktop classpath there is
+# no android.os.Parcelable. We never use AndroidMessage on desktop.
+-dontwarn com.squareup.wire.AndroidMessage
+-dontwarn com.squareup.wire.AndroidMessage$*
+-dontwarn android.os.Parcelable
+-dontwarn android.os.Parcelable$*
--dontwarn kotlin.concurrent.atomics.**
--dontwarn kotlin.uuid.UuidV7Generator
-
-# ---- Library consumer rules ------------------------------------------------
-# The compose-jb gradle plugin auto-injects `default-compose-desktop-rules.pro`
-# (bundled inside org.jetbrains.compose:compose-gradle-plugin) into every
-# desktop ProGuard run. That file already covers:
-# - kotlin.**, kotlinx.coroutines.** (incl. SwingDispatcherFactory ServiceLoader)
-# - org.jetbrains.skiko.**, org.jetbrains.skia.**
-# - kotlinx.serialization.** (incl. @Serializable companion keeps)
-# - kotlinx.datetime.**
-# - androidx.compose.runtime SnapshotStateKt + Material3 SliderDefaults
-# So we DO NOT re-declare those here. Source of truth:
-# https://github.com/JetBrains/compose-multiplatform/blob/master/gradle-plugins/compose/src/main/resources/default-compose-desktop-rules.pro
-#
-# However, the standalone ProGuard 7.7.0 that compose-jb invokes does NOT
-# auto-import library `META-INF/proguard/*.pro` consumer rules from arbitrary
-# jars (only R8/Android does). So any consumer-rule pattern outside the bundled
-# defaults above must be copied here manually (see Ktor SL block below).
-
-# ---- androidx.sqlite bundled driver (JNI native bridge) ---------------------
-# BundledSQLiteDriver loads `libsqliteJni` and the native code calls back into
-# JVM-land via methods on `BundledSQLiteDriverKt` (e.g. `nativeThreadSafeMode`)
-# and member methods on `BundledSQLiteDriver` itself. Because those JVM symbols
-# are referenced only from native code, ProGuard removes them as unused; the
-# native loader then crashes with `NoSuchMethodError: ... name or signature does
-# not match`. Keep the whole driver package β€” it's small and entirely needed at
-# runtime once the bundled SQLite driver is selected.
--keep class androidx.sqlite.driver.bundled.** { *; }
--keepclassmembers class androidx.sqlite.driver.bundled.** { native <methods>; *; }
-
-# ---- Ktor serialization extension providers (ServiceLoader) -----------------
-# io.ktor.serialization.kotlinx-json discovers KotlinxSerializationJsonExtensionProvider
-# via META-INF/services/io.ktor.serialization.kotlinx.KotlinxSerializationExtensionProvider.
-# Without this keep the desktop HttpClient init throws ServiceConfigurationError
-# at first request; on Windows jpackage's launcher swallows the trace and
-# surfaces it as "Failed to launch JVM".
--keep class * implements io.ktor.serialization.kotlinx.KotlinxSerializationExtensionProvider { *; }
-
-# ---- Vico 3.2.0-next.1 ColorScale (CMP API drift) ---------------------------
-# Vico's new ColorScale* classes (ColorScaleShader, ColorScaleAreaFill,
-# ColorScaleLineFill) reference CMP UI graphics members that don't exist in
-# compose-multiplatform 1.11.0-beta03 (LinearGradientShader-VjE6UOU$default
-# on ShaderKt and Paint.setShader(org.jetbrains.skia.Shader)). We don't use
-# the ColorScale APIs in this app, so suppress these warnings to let ProGuard
-# proceed; otherwise it aborts with "unresolved program class members".
-# Remove once Vico ships a release built against CMP 1.11 stable.
+# Vico's ColorScale* classes call into skia-shader bridges that aren't on the
+# desktop ProGuard classpath. Vico ships no consumer rules.
-dontwarn com.patrykandpatrick.vico.compose.cartesian.ColorScaleShader
-dontwarn com.patrykandpatrick.vico.compose.cartesian.layer.ColorScaleAreaFill
-dontwarn com.patrykandpatrick.vico.compose.cartesian.layer.ColorScaleLineFill
+
+# ---- Kotlin 2.3+ stdlib intrinsics not present on JDK 17 --------------------
+-dontwarn kotlin.concurrent.atomics.**
+-dontwarn kotlin.uuid.UuidV7Generator

diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 550d9dc20f..09818fc27d 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -44,9 +44,9 @@ compose-multiplatform-material3 = "1.11.0-alpha07"
# AndroidCompose.kt's resolutionStrategy force-aligns these groups to *this* version
# at resolution time, so it is the source of truth for the Android target.
androidx-compose-bom-aligned = "1.11.0"
-# `androidx-compose-material` (M2) is independent of CMP and pinned separately
-# because some third-party libs (maps-compose-widgets, datadog) drag in
-# unversioned material transitives.
+# `androidx-compose-material` (M2) is independent of CMP. Pinned because
+# maps-compose-widgets requests `androidx.compose.material:material` without
+# a version (relying on a BOM that we exclude). M2 is frozen at 1.7.8.
androidx-compose-material = "1.7.8"
jetbrains-adaptive = "1.3.0-alpha07"

Served by rngit 1.5.4 - Generated in 0.06s